package io.geekidea.boot.webStock.handler;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import io.geekidea.boot.jab.dto.PushMessageDto;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@ChannelHandler.Sharable
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    // 存储visitorId和ChannelHandlerContext的映射关系
    private static final ConcurrentHashMap<String, ChannelHandlerContext> VISITOR_CHANNELS = new ConcurrentHashMap<>();
    
    // 存储visitorId和最后心跳时间的映射关系
    private static final ConcurrentHashMap<String, Long> LAST_HEARTBEAT_TIME = new ConcurrentHashMap<>();
    
    // 心跳超时时间（毫秒）
    private static final long HEARTBEAT_TIMEOUT = TimeUnit.SECONDS.toMillis(90);

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        log.info("New client connected: {}", ctx.channel().remoteAddress());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        // 移除断开的连接
        VISITOR_CHANNELS.entrySet().removeIf(entry -> entry.getValue().equals(ctx));
        // 移除心跳记录
        LAST_HEARTBEAT_TIME.entrySet().removeIf(entry -> VISITOR_CHANNELS.get(entry.getKey()) == null);
        log.info("Client disconnected: {}", ctx.channel().remoteAddress());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
        try {
            String messageText = msg.text();
            JSONObject jsonObject = JSON.parseObject(messageText);
            String visitorId = jsonObject.getString("visitorId");
            
            if (visitorId != null) {
                // 存储visitorId和连接的映射关系
                VISITOR_CHANNELS.put(visitorId, ctx);
                //心跳与ctx对应关系
                log.info("Client heartbeat: {}", visitorId+"--"+ctx.channel().remoteAddress());
                // 如果消息只包含visitorId，则视为心跳消息
                if (jsonObject.size() == 1) {
                    LAST_HEARTBEAT_TIME.put(visitorId, System.currentTimeMillis());
                    log.debug("Received heartbeat from visitor: {}", visitorId);
                }
            }
        } catch (Exception e) {
            log.error("Error processing message: {}", msg.text(), e);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("WebSocket error", cause);
        ctx.close();
    }

    /**
     * 定期检查心跳超时
     * 每30秒执行一次
     */
    @Scheduled(fixedRate = 30000)
    public void checkHeartbeat() {
        long currentTime = System.currentTimeMillis();
        LAST_HEARTBEAT_TIME.forEach((visitorId, lastHeartbeat) -> {
            if (currentTime - lastHeartbeat > HEARTBEAT_TIMEOUT) {
                ChannelHandlerContext ctx = VISITOR_CHANNELS.get(visitorId);
                if (ctx != null) {
                    log.warn("Heartbeat timeout for visitor: {}, closing connection", visitorId);
                    ctx.close();
                    // 清理相关数据
                    VISITOR_CHANNELS.remove(visitorId);
                    LAST_HEARTBEAT_TIME.remove(visitorId);
                }
            }
        });
    }

    /**
     * 发送消息给指定的访客
     */
    public void sendMessageToVisitor(String visitorId, PushMessageDto message) {
        ChannelHandlerContext ctx = VISITOR_CHANNELS.get(visitorId);
        if (ctx != null && ctx.channel().isActive()) {
            String messageJson = JSON.toJSONString(message);
            ctx.channel().writeAndFlush(new TextWebSocketFrame(messageJson));
            log.info("Message sent to visitor {}: {}", visitorId, messageJson);
        } else {
            log.warn("Visitor {} not found or channel inactive", visitorId);
        }
    }

    /**
     * 检查访客是否在线
     */
    public boolean isVisitorOnline(String visitorId) {
        ChannelHandlerContext ctx = VISITOR_CHANNELS.get(visitorId);
        return ctx != null && ctx.channel().isActive();
    }
} 